<script setup lang="ts">
import { computed, nextTick, onUnmounted, ref, watch } from "vue";
import moment from 'moment'
import { timeDifference } from '@/utils/gps/player'
import axios from 'axios'
import { nanoid } from 'nanoid'
import { jt1078Heart } from '@/api/gps/command'
import { VideoPause, VideoPlay } from "@element-plus/icons-vue"

interface Props {
  modelValue?: {
    playing: boolean,
    preparing: boolean,
    totalTime: number,
    playedTime: number,
    speed: number,
    over: boolean,
  }
  videoData?: {
    plateNoName: string
    plateNo: string
    index: number
  }
  control?: boolean
}
// @ts-ignore
const props = withDefaults(defineProps<Props>(), {
  control: false,
})

const emits = defineEmits(['close','update:modelValue'])

const container = ref()
const playerRef = ref<HTMLDivElement>()
const innerRef = ref<HTMLDivElement>()
const dotRef = ref<HTMLDivElement>()
const subtitlesText = ref('连接成功，等待设备响应')
let jessibuca: any
let timer
let videoTimer
let cancelFun
let heartTimer
let PLAY_URL = ""

let oldTs = -1
let count = 0

const state = ref({
  playing: false,
  preparing: false,
  totalTime: 0,
  playedTime: 0,
  speed: 1,
  over: true
})

watch(()=> props.modelValue, (val)=>{
  state.value = val || {
    playing: false,
    preparing: false,
    totalTime: 0,
    playedTime: 0,
    speed: 1,
    over: false}
}, {immediate: true, deep: true})

watch(state, (val)=>{
  emits("update:modelValue", val)
})

watch(()=> state.value.over, (val)=>{
  // 先判断视频是否已经在播放中，如果是就关闭视频并改变播放状态
  if(val) {
    jessibuca.isPlaying() && (jessibuca.close() || true) && (state.value.playing = false);
    oldTs = -1
  }
})

const playedTime = computed(() => {
  return state.value.playedTime
})
const totalTime = computed(() => {

  return state.value.totalTime
})
const dataContent = computed(() => {
  return props.videoData ? `${props.videoData.plateNoName}-${props.videoData.plateNo}` : ''
})

// 已播放进度
const playedProgress = computed(() => {
  return `width: ${(playedTime.value * 100) / totalTime.value}%`
})
// 已加载进度
const loadedProgress = computed(() => {
  // return `width: ${(bufTime.value * 100) / totalTime.value}%`
  return `width: ${0 / totalTime.value}%`
})
// 进度条实际宽度
const progressBarWidth = computed(() => {
  return innerRef.value?.offsetWidth
})

/**
 * 播放
 */
function player(url) {
  state.value.preparing = false
  state.value.over = false
  console.log("加载完成");
  jessibuca.play(url)
}

function playAndPauseEvent(){
  state.value.playing = !state.value.playing
}

/**
 * 初始化进度条事件
 */
function initProgressBarEvent() {
  innerRef.value?.addEventListener('click', progressBarClick)
  // setInterval(() => {}, 1000)
}

// function progressBarClick(event: PointerEvent) {
//   console.log(event.offsetX)
// }

function progressBarClick(evt: PointerEvent) {
  console.log(evt.offsetX / progressBarWidth.value)
}
function createVideo() {
  jessibuca = new (window as any).Jessibuca({
    container: container.value,
    videoBuffer: 0.2, // 设置最大缓冲时长，单位毫秒，播放器会自动消除延迟。
    forceNoOffscreen: true, // 是否不使用离屏模式（提升渲染能力）
    hasAudio: true, // 是否有音频
    rotate: 0, // 设置旋转角度，只支持，0(默认) ，180，270 三个值
    isResize: false, // 1.当为true的时候：视频画面做等比缩放后,高或宽对齐canvas区域,画面不被拉伸,但有黑边;2.当为false的时候：视频画面完全填充canvas区域,画面会被拉伸
    isFullSize: true, // 当为true的时候：视频画面做等比缩放后,完全填充canvas区域,画面不被拉伸,没有黑边,但画面显示不全
    debug: false, // 是否开启控制台调试打印
    timeout: 30, // 设置超时时长, 单位秒,在连接成功之前和播放中途,如果超过设定时长无数据返回,则回调timeout事件
    supportDblclickFullscreen: true, // 是否支持屏幕的双击事件，触发全屏，取消全屏事件。
    showBandwidth: true, // 是否显示网速
    operateBtns: {
      fullscreen: true, // 是否显示全屏按钮
      screenshot: true, // 是否显示截图按钮
      play: true, // 是否显示播放暂停按钮
      audio: true, // 是否显示声音按钮
      recorder: false
    },
    keepScreenOn: false, // 开启屏幕常亮，在手机浏览器上, canvas标签渲染视频并不会像video标签那样保持屏幕常亮。
    isNotMute: true, // 是否开启声音，默认是关闭声音播放的。
    loadingText: '正在加载视频资源', // 加载过程中文案。
    background: '', // 背景图片。
    decoder: '/jessibuca/decoder.js',
    // useMSE: false,
    isFlv: true,
    controlAutoHide: true // 只有鼠标聚焦到播放器内部才会显示控制台，移除之后，会消失
  })

  jessibuca.on('stats', function ({ ts, buf }) {
    // console.log(ts, oldTs, ts - oldTs, count);
    if(oldTs > 0){
      state.value.playedTime += ts - oldTs
      count += (ts - oldTs)
    }
    oldTs = ts
  })
  jessibuca.on('pause', function () {
    console.log("暂停")
    stopTimer()
    state.value.playing = false
  })

  jessibuca.on('play', function () {
    console.log("播放")
    runTimer()
    state.value.playing = true
  })
  jessibuca.on("delayTimeout", function () {
    console.log('timeout')
  })
}

function queryPlaybackResources() {}

/**
 * 开启计时器
 */
function runTimer(){
  videoTimer = setInterval(()=>{

  },1000)
}
function stopTimer(){
  clearInterval(videoTimer)
}

/**
 * 提供给外部初始化方法-需要传递一个异步方法，响应结果为播放资源
 * 并对外提供两个的方法和一个配置
 * @param callback - play: 播放 fail: 失败 config：请求配置-cancelToken取消上一次请求
 * @param heartbeatEnabled - 失败重连 true为开启
 */
function init(callback: (player: { play: (url: string, key: string) => void; fail: () => void; config: any }) => void, heartbeatEnabled = false) {
  playerRef.value?.classList.add('loading', 'playing')
  if (!jessibuca) {
    createVideo()
    props.control && initProgressBarEvent()
  }
  open()
  /**
   * 播放
   * @param url
   * @param key
   */
  function play(url: string, key: string) {
    finish()
    player(url)
    startHeart(key)
  }
  /**
   * 错误
   */
  function fail() {
    if (heartbeatEnabled && jessibuca) {
      subtitlesText.value = '设备未响应，将在5s后发起重连'
      timer = setTimeout(() => {
        open()
      }, 5000)
    }
  }
  /**
   * 完成
   */
  function finish() {
    cancelFun = null
    playerRef.value?.classList.remove('loading')
    if(heartTimer){
      clearInterval(heartTimer)
      heartTimer = null
    }
  }
  /**
   * 连接
   */
  function open() {
    subtitlesText.value = '等待设备响应'
    callback({ play, fail, config: { cancelToken: new axios.CancelToken((c) => (cancelFun = c)) } })
  }
  /**
   * 心跳
   * @param heartKey
   */
  function startHeart(heartKey: string) {
    jt1078Heart(heartKey).then(() => {})
    heartTimer = setTimeout(() => {
      startHeart(heartKey)
    }, 15000)
  }
}
function closeHandle() {
  emits('close', props.videoData?.index)
  closeVideoWindow()
}

/**
 * 销毁播放器
 */
function closeVideoWindow() {
  state.value.over = true
  state.value.playing = false
  state.value.preparing = false
  state.value.totalTime = 0
  state.value.playedTime = 0
  state.value.speed = 1
  nextTick(()=>{
    destroyEvent()
    playerRef.value?.classList.remove('loading', 'playing')
  })
}

function destroyEvent(){
  if (jessibuca) {
    jessibuca.destroy()
    jessibuca = null
  }
  cancelFun?.()
  if (timer) {
    clearTimeout(timer)
    timer = null
  }
  if (heartTimer) {
    clearTimeout(heartTimer)
    heartTimer = null
  }
}

onUnmounted(() => {
  destroyEvent()
})

defineExpose({
  init,
  closeVideoWindow
})
</script>

<template>
  <div ref="playerRef" class="player" :data-content="dataContent" :data-subtitles="subtitlesText">
    <div :id="`tc-player-${nanoid()}`" ref="container" :style="`height: calc(100% - ${props.control ? 30 : 0}px)`"></div>
    <div v-if="props.control" class="control">
      <div class="control_speed">
        <el-select v-model="state.speed" size="small">
          <el-option label="正常" :value="1"></el-option>
          <el-option label="x2" :value="2"></el-option>
          <el-option label="x4" :value="3"></el-option>
          <el-option label="x8" :value="4"></el-option>
          <el-option label="x16" :value="5"></el-option>
        </el-select>
      </div>
      <div class="play_pause">
        <ElIcon size="20" @click="playAndPauseEvent" style="transform: translateY(1px);">
          <VideoPause v-if="state.playing"/>
          <VideoPlay v-else/>
        </ElIcon>
      </div>
      <div class="player_played">
        {{ moment.utc(playedTime).format("HH:mm:ss") }}
      </div>
      <div class="player_progress">
        <div ref="innerRef" class="player_progress__inner">
          <div class="player_progress__load" :style="loadedProgress"></div>
          <div class="player_progress__play" :style="playedProgress">
            <i ref="dotRef" class="player_progress__dot"></i>
          </div>
        </div>
      </div>
      <div class="player_total">
        {{ moment.utc(totalTime).format("HH:mm:ss") }}
      </div>
    </div>
    <img src="../../assets/close_white.png" alt="" class="video_close" @click="closeHandle" />
    <div class="mask"></div>
  </div>
</template>

<style scoped lang="scss">
.player {
  box-sizing: border-box;
  border: 1px solid white;
  height: 100%;
  position: relative;
}
.control {
  height: 30px;
  box-sizing: border-box;
  width: 100%;
  background-color: #fff;
  display: flex;
  align-items: center;
  padding: 1px 20px;
}
.control_speed {
  width: 80px;
  margin-right: 15px;
}
.player_progress {
  flex: 1;
  height: 5px;
  cursor: pointer;
  margin: 0 10px;
}
.player_progress__inner {
  position: relative;
  height: 5px;
  background: #9999991a;
}
.player_progress__load {
  height: 5px;
  background: #9993;
}
.player_progress__play {
  position: absolute;
  top: 0;
  left: 0;
  height: 5px;
  background: #409effb3;
}
.player_progress__dot {
  top: -4px;
  right: -4px;
  width: 10px;
  height: 10px;
  background-position: 0 -170px;
  position: absolute;
  background-image: url('@/assets/player-icon.png');
  opacity: 1;
  filter: alpha(opacity = 80);
  border: 2px solid rgb(64, 158, 255);
  border-radius: 50%;
}
.video_close {
  position: absolute;
  z-index: 101;
  top: 5px;
  right: 5px;
  width: 16px;
  height: 16px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s;
  cursor: pointer;
}
.mask {
  position: absolute;
  inset: 0;
  opacity: 0;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 100;
  transition: opacity 0.5s;
  pointer-events: none;
}
.loading::before {
  opacity: 1 !important;
}
.loading .mask {
  opacity: 1;
  pointer-events: auto;
}
.playing:hover .video_close {
  opacity: 1;
  pointer-events: auto;
}
.playing:hover::after {
  opacity: 0;
}

.player::before {
  content: attr(data-subtitles);
  color: white;
  position: absolute;
  width: 90%;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 111;
  opacity: 0;
  transition: opacity 0.5s;
  text-align: center;
  pointer-events: none;
}
.player::after {
  content: attr(data-content);
  pointer-events: none;
  position: absolute;
  width: 100%;
  display: inline-block;
  color: #fc3b3b;
  text-align: center;
  font-weight: 700;
  z-index: 999;
  bottom: 1%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.play_pause{
  margin-right: 5px;
  cursor: pointer;
}
</style>
